#include <iostream> 
#include <vector>
#include <boost/random.hpp>
#include <boost/lexical_cast.hpp>
#include "kuaicu.h"
#include <ctime>

using namespace std;
using namespace kuai;


/*
extern void test1(kuai::cuda::FloatArray& a, const kuai::cuda::FloatArray& v1, const kuai::cuda::FloatArray& v2);
extern void test2(kuai::cuda::FloatArray& a, const kuai::cuda::FloatArray& v1, const kuai::cuda::FloatArray& v2);
extern void test3(kuai::cuda::FloatArray& a, const kuai::cuda::FloatArray& v1, const kuai::cuda::FloatArray& v2);


int main(int argc, char* argv[]) {
	int n = boost::lexical_cast<int>(argv[1]);
	int loop = boost::lexical_cast<int>(argv[2]);
	
	RealArray x, y;
	x.reserve(n); y.reserve(n);

	boost::mt19937 rng(0);
	boost::uniform_real<RealNumber> distribution(-10, 10);
	boost::variate_generator<boost::mt19937&, boost::uniform_real<RealNumber> >
           die(rng, distribution);

	for (int i = 0; i < n; ++i) {
		x.push_back(die());
		y.push_back(die());
	}

	try {
		cuda::FloatArray xc(x);
		cuda::FloatArray yc(y);
		cuda::FloatArray result(n);

		clock_t t1 = clock();
		test1(result, xc, yc);
		for (int i = 0; i < loop; ++i) {
			test1(result, result, yc);
		}
		clock_t t2 = clock();

		test2(result, xc, yc);
		for (int i = 0; i < loop; ++i) {
			test2(result, result, yc);
		}

		clock_t t3 = clock();
		test3(result, xc, yc);
		for (int i = 0; i < loop; ++i) {
			test3(result, result, yc);
		}

		clock_t t4 = clock();

		std::cout << "T1: " << t2-t1 << std::endl;
		std::cout << "T2: " << t3-t2 << std::endl;
		std::cout << "T3: " << t4-t3 << std::endl;

	}
	catch (ErrorMessage& err) {
		std::cerr << err.what() << std::endl;
	}
}
*/

/*
int main(int argc, char* argv[]) {
	int nAtoms = boost::lexical_cast<int>(argv[1]);
	int nsteps = boost::lexical_cast<int>(argv[2]);

	boost::mt19937 rng(0);
	boost::uniform_real<RealNumber> distribution(-10, 10);
	boost::variate_generator<boost::mt19937&, boost::uniform_real<RealNumber> >
           die(rng, distribution);

	RealArray coords; coords.reserve(nAtoms*3);
	RealArray mass; mass.reserve(nAtoms);

	for (int i = 0; i < nAtoms; ++i) {
		coords.push_back(die());
		coords.push_back(die());
		coords.push_back(die());
		mass.push_back(die()+11);
	}

	cublasInit();

	try {
		cuda::FloatArray coordsInCuda(coords, false);
		cuda::FloatArray massInCuda(mass, false);
		cuda::FloatArray rmass(mass.size());
		rmass.rev(massInCuda);

		cuda::FloatArray speedsInCuda(nAtoms*3);
		cuda::FloatArray forcesInCuda(nAtoms*3);
		cuda::FloatArray acceleration(nAtoms*3);

		cuda::FloatArray forcesX(forcesInCuda, 0, nAtoms*3, 3);
		cuda::FloatArray forcesY(forcesInCuda, 1, nAtoms*3, 3);
		cuda::FloatArray forcesZ(forcesInCuda, 2, nAtoms*3, 3);
		
		cuda::FloatArray accelerationX(acceleration, 0, nAtoms*3, 3);
		cuda::FloatArray accelerationY(acceleration, 1, nAtoms*3, 3);
		cuda::FloatArray accelerationZ(acceleration, 2, nAtoms*3, 3);

		float half_step = 0.5;
		float one_step = 1;
		for (int i = 0; i < nsteps; ++i) {
			coordsInCuda.add_ax(half_step, speedsInCuda);	// x += 0.5 * v;
			// forcesInCuda	// Update
			accelerationX.mul(forcesX, rmass);
			accelerationY.mul(forcesY, rmass);
			accelerationZ.mul(forcesZ, rmass);

			speedsInCuda.add_ax(one_step, acceleration);
			coordsInCuda.add_ax(half_step, speedsInCuda);	// x += 0.5 * v;
		}
	}
	catch (ErrorMessage& err) {
		std::cerr << err.what() << std::endl;
	}

	cublasShutdown();
	return 0;
}
*/

/*
namespace kuai { namespace cuda { 
	
	extern void testTime(
		const FloatArray& x, const Array<int> list, 
		FloatArray& result, Array<clock_t>& time);

	void testTime() {

		std::vector<float> x(1000, 1.0);
		std::vector<int> list(1000);
		for (int i = 0; i < 1000; ++i) {
			list[i] = i;
		};
		FloatArray xInCuda(x);
		Array<int> listInCuda(list);
		FloatArray result(1000);
		Array<clock_t> delta(1024);
		 
		testTime(xInCuda, listInCuda, result, delta);

		std::random_shuffle(list.begin(), list.end());
		Array<int> list2InCuda(list);
		testTime(xInCuda, list2InCuda, result, delta);

	}

} }

int main(int argc, char* argv[]) {


	kuai::cuda::testTime();


}

*/
namespace kuai { namespace cuda {

	FloatArray workbuffer(MAX_BLOCKS);

} }


int main(int argc, char* argv[]) {

	boost::mt19937 rng(0);
	boost::uniform_real<RealNumber> distribution(-10, 10);
	boost::variate_generator<boost::mt19937&, boost::uniform_real<RealNumber> >
           die(rng, distribution);

	try {
		int n = 1;
		for (size_t i =1; i <= 10; ++i) {
			std::vector<float> f(n*i);
			float f1 = 0;
			for (size_t j = 0; j < f.size(); ++j) {
				f[j] = die();
				f1 += f[j];
			}
			kuai::cuda::FloatArray ff(f);
			float f2 = ff.sum();
			std::cout << f1 << "\t" << f2 << "\t" << f1-f2 << std::endl;
			/*
			ff.get(f);
			for (size_t j = 0; j < f.size(); ++j) {
				std::cout << j << ": " << f[j] << std::endl;
			}
			*/
		}
	}
	catch (exception& error) {
		std::cerr << "#Error: " << error.what() << std::endl;
	}

}
